package com.yiwan.app.preventionsis.config;

import android.app.Application;
import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;
import com.app.tianwan.tianwanframe.utils.FileUtils;
import com.app.tianwan.tianwanframe.utils.LogUtil;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.yiwan.app.preventionsis.bean.ImageRes;
import com.yiwan.app.preventionsis.bean.ResVersion;
import com.yiwan.app.preventionsis.util.StorageUtil;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

/**
 * 图片资源管理器
 */
public class ImageResManager {

    private static final String RES_FOLDER_IN_ASSETS = "res_dir";
    /**
     * 文件读写流buffer大小
     */
    private static final int BUFF_SIZE = 8192;

    private static ImageResManager instance;
    private Context context;

    /** 图片资源版本 **/
    private int resVersionCode;
    private List<ImageRes> imgIntro;
    private List<ImageRes> imgCheet;
    private List<ImageRes> imgFire;
    private List<ImageRes> imgRob;
    private List<ImageRes> imgSteal;
    private List<ImageRes> imgSelfSave;
    private List<ImageRes> imgterror;

    private ImageResManager(){}

    public static ImageResManager init(Application application){
        if (instance == null){
            instance = new ImageResManager();
            instance.context = application.getApplicationContext();
        }
        return instance;
    }

    public static ImageResManager getInstance(){
        if(instance == null){
            throw new NullPointerException("ImageResManager not initiated");
        }
        return instance;
    }

    public int getResVersion() throws IOException{
        if(resVersionCode == 0){
            resVersionCode = loadVersion();
        }
        return resVersionCode;
    }

    public List<ImageRes> getImgIntro() {
        return imgIntro;
    }

    public List<ImageRes> getImgCheet() {
        return imgCheet;
    }

    public List<ImageRes> getImgFire() {
        return imgFire;
    }

    public List<ImageRes> getImgRob() {
        return imgRob;
    }

    public List<ImageRes> getImgSteal() {
        return imgSteal;
    }

    public List<ImageRes> getImgSelfSave() {
        return imgSelfSave;
    }

    public List<ImageRes> getImgterror() {
        return imgterror;
    }

    public int loadRes() throws IOException{
        loadVersion();
        imgIntro = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_INTRO + File.separator + GlobalCfg.IMG_CONFIG_INTRO);
        imgCheet = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_CHEAT + File.separator + GlobalCfg.IMG_CONFIG_CHEAT);
        imgFire = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_FIRE + File.separator + GlobalCfg.IMG_CONFIG_FIRE);
        imgRob = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_ROB + File.separator + GlobalCfg.IMG_CONFIG_ROB);
        imgSteal = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_STEAL + File.separator + GlobalCfg.IMG_CONFIG_STEAL);
        imgSelfSave = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_SELFSAVE + File.separator + GlobalCfg.IMG_CONFIG_SELFSAVE);
        imgterror = loadImageRes(GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.FOLER_IMG_TERROR + File.separator + GlobalCfg.IMG_CONFIG_TERROR);
        return resVersionCode;
    }

    public int loadVersion() throws IOException{
        try{
            Gson gson = new Gson();
            String versionStr = FileUtils.readMemFile(context, GlobalCfg.RES_FOLDER + File.separator + GlobalCfg.VERSION_DAT);
            resVersionCode = Integer.parseInt(gson.fromJson(versionStr, ResVersion.class).getVersion());
            return resVersionCode;
        } catch (NumberFormatException e){
            return 0;
        } catch (JsonSyntaxException e) {
            throw new IOException(e);
        }
    }

    private List<ImageRes> loadImageRes(String configFilePath) throws IOException{
        String imgConfigJson = FileUtils.readMemFile(context, configFilePath);
        LogUtil.d(configFilePath + ": " + imgConfigJson);
        Gson gson = new Gson();
        return gson.fromJson(imgConfigJson, new TypeToken<List<ImageRes>>(){}.getType());
    }

    public void initRes() throws IOException{
        //从asset中拷贝并解压资源
        String assetFolder = RES_FOLDER_IN_ASSETS;
        String targetUnZipFolder = GlobalCfg.RES_FOLDER;
        File imgFolder = new File(StorageUtil.getAppFilePath().getAbsolutePath()
                + File.separator + targetUnZipFolder);
        boolean deleteRes = imgFolder.delete();
        copyAndUnzipAssets(assetFolder, targetUnZipFolder);
    }

    public void initDownloadRes(String downloadFile) throws IOException{
        //从下载目录中解压文件
        String targetFolder = GlobalCfg.RES_FOLDER;
        String targetPathStr = StorageUtil.getAppFilePath().getAbsolutePath() + File.separator + targetFolder;
        File targetPath = new File(targetPathStr);
        boolean deleteRes = targetPath.delete();

        long time1 = System.currentTimeMillis();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        Date d1 = new Date(time1);
        LogUtil.d("Unzipped start " + format.format(d1) + ", zip path " + downloadFile + ", target path " + targetPath);
        unzipFile(targetPathStr, downloadFile);
//                        readByZipInputStream(zipFilePath,  targetPath);
        long time2 = System.currentTimeMillis();
        Date d2 = new Date(time2);
        LogUtil.d("Unzipped start " + format.format(d2));

        LogUtil.d("Unzipped time " + format.format(new Date(time2 - time1)));
    }

    /**
     * 拷贝assets数据到外部存储器并解压
     */
    private void copyAndUnzipAssets(String assetFolder, String targetFolder) throws IOException{
        //Copy Zipped File
        String[] files;
        AssetManager am = context.getAssets();
        try {
            files = am.list(assetFolder);
        } catch (IOException e1) {
            return;
        }
        File cachePath = new File(StorageUtil.getAppCachePath().getAbsolutePath());

        String fileName = null;
        InputStream in;
        OutputStream out;
        for (int i = 0; i < files.length; i++) {
            fileName = files[i];
            // we make sure file name not contains '.' to be a folder.
            if (fileName.endsWith(".zip")) {
                in = am.open(assetFolder + File.separator + fileName, AssetManager.ACCESS_UNKNOWN);

                File outFile = new File(cachePath, fileName);
                boolean deleteRes = false;
                if (outFile.exists())
                    deleteRes = outFile.delete();
                out = new FileOutputStream(outFile);

                // Transfer bytes from in to out
                byte[] buf = new byte[BUFF_SIZE];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                in.close();
                out.close();

                String zipFilePath = StorageUtil.getAppCachePath().getAbsolutePath() + File.separator + fileName;
                String targetPath = StorageUtil.getAppFilePath() + File.separator + targetFolder;
                File unzipFolder = new File(targetPath);
                if(unzipFolder.exists()){
                    deleteRes = unzipFolder.delete();
                }
                long time1 = System.currentTimeMillis();
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
                Date d1 = new Date(time1);
                LogUtil.d("Unzipped start" + format.format(d1));
                unzipFile(targetPath, zipFilePath);
//                        readByZipInputStream(zipFilePath,  targetPath);
                long time2 = System.currentTimeMillis();
                Date d2 = new Date(time2);
                LogUtil.d("Unzipped start" + format.format(d2));

                LogUtil.d("Unzipped time" + format.format(new Date(time2 - time1)));
            }
        }
    }

    /**
     * 解压zip文件，可包含中文路径
     *
     * @param targetPath  解压至
     * @param zipFilePath 待解压文件
     */
    public void unzipFile(String targetPath, String zipFilePath) throws IOException{
        ZipFile zipFile = new ZipFile(zipFilePath, "GBK");
        Enumeration enumeration = zipFile.getEntries();
        while (enumeration.hasMoreElements()) {
            ZipEntry ze = (ZipEntry)enumeration.nextElement();
            String entryName = ze.getName();
            String path = targetPath + File.separator + entryName;
            try{
                if(ze.isDirectory()){
                    File decompressDirFile = new File(path);
                    if(!decompressDirFile.exists()){
                        decompressDirFile.mkdir();
                    }
                } else {
                    File decompressFile = new File(path);
//                    if(!decompressFile.exists()){
                        String fileDir = path.substring(0, path.lastIndexOf("/"));
                        File fileDirFile = new File(fileDir);
                        if (!fileDirFile.exists()) {
                            fileDirFile.mkdirs();
                        }
                        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetPath + File.separator + entryName));
                        BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(ze));
                        byte buffer[] = new byte[BUFF_SIZE];
                        int realLength;
                        while ((realLength = bis.read(buffer)) != -1) {
                            bos.write(buffer, 0, realLength);
                        }
                        bos.flush();
                        bos.close();
//                    }
                }
                Log.d("unzipFile", "成功解压:" + entryName);
            } catch (Exception e) {
                Log.d("unzipFile", "解压" + entryName + "失败");
                e.printStackTrace();
            }
        }
        zipFile.close();
        Log.d("unzipFile", "解压结束");
    }
}
